package com.tools.common.security.id;

import com.tools.common.exception.InvalidOperationException;
import com.tools.common.object.Note;

import java.util.Random;
import java.util.TreeSet;
import java.util.UUID;

/**
 * ID 序列号生成器工具类
 * */
@Note("ID 序列号生成器工具类")
public final class IDKit {

    private IDKit() {}

    @Note("自定义数字 ID 生成器实例")
    private static volatile NumberID NUMBER_ID_ENTITY;

    @Note("雪花 ID 生成器实例")
    private static volatile SnowFlakeID SNOW_FLAKE_ID_ENTITY;

    @Note("字符串 ID 生成器实例")
    private static volatile StringID STRING_ID_ENTITY;

    /* *******************************************************************************************
     *
     *          字符串 ID
     *
     * *******************************************************************************************
     * */



    @Note("生成一个 UUID 返回")
    public static String newUUID() {
        return UUID.randomUUID().toString();
    }


    @Note("生成一个 UUID ，然后将【-】去掉返回")
    public static String newUUID2() {
        return UUID.randomUUID().toString().replace("-", "");
    }


    @Note("生成一个 UUID，并用 replaceChar 替换 UUID 的【-】字符后返回")
    public static String newUUID(String replaceChar) {
        String uuid = newUUID();
        return uuid.replace("-", replaceChar);
    }


    @Note("懒加载字符串 ID 生成器实例")
    public static StringID getStringIDEntity() {
        if(STRING_ID_ENTITY != null) return STRING_ID_ENTITY;
        synchronized (IDKit.class) {
            if(STRING_ID_ENTITY != null) return STRING_ID_ENTITY;
            STRING_ID_ENTITY = new StringID();
            return STRING_ID_ENTITY;
        }
    }


    @Note("使用默认的随机数生成器、默认的字符模板数组、默认的长度生成一个 NanoID 返回")
    public static String newNanoID() {
        return getStringIDEntity().newNanoID();
    }


    @Note("返回一个指定长度的 NanoID")
    public static String newNanoID(int length) {
        return getStringIDEntity().newNanoID(length);
    }


    @Note("使用指定的随机数生成器、指定的字符模板数组、指定的长度生成一个 NanoID 返回")
    public static String newNanoID(Random random, char[] charArrayTemplate, int length) {
        return getStringIDEntity().newNanoID(random, charArrayTemplate, length);
    }


    @Note("使用默认的字符模板数组，获取长度为默认长度的字符串 ID 返回")
    public static String newStringID() {
        return getStringIDEntity().newStringID();
    }


    @Note("使用默认的字符模板数组，获取长度为 length 的字符串 ID 返回")
    public static String newStringID(int length) {
        return getStringIDEntity().newStringID(length);
    }


    @Note("使用指定的字符模板数组，获取长度为 length 的字符串 ID 返回")
    public static String newStringID(int length, char[] charTemplate){
        return getStringIDEntity().newStringID(length, charTemplate);
    }

    @Note("获取指定长度的十六进制的随机字符串")
    public static String new16BinaryID(int length) {
        return getStringIDEntity().new16BinaryID(length);
    }

    /* *******************************************************************************************
     *
     *          数字 ID 方法区
     *
     * *******************************************************************************************
     * */

    @Note("懒加载数字 ID 生成器实例")
    public static NumberID getNumberIDEntity() {
        if(NUMBER_ID_ENTITY != null) return NUMBER_ID_ENTITY;
        synchronized (IDKit.class) {
            if(NUMBER_ID_ENTITY != null) return NUMBER_ID_ENTITY;
            NUMBER_ID_ENTITY = new NumberID();
            return NUMBER_ID_ENTITY;
        }
    }


    @Note("初始化雪花 ID 生成器实例")
    public static void initSnowFlakeIDEntity(long workerId, long datacenterId, long sequence) {
        if(SNOW_FLAKE_ID_ENTITY != null) return;
        synchronized (IDKit.class) {
            if(SNOW_FLAKE_ID_ENTITY != null) return;
            SNOW_FLAKE_ID_ENTITY = new SnowFlakeID(workerId, datacenterId, sequence);
        }
    }


    @Note("获取本工具类默认的雪花 ID 生成器")
    public static SnowFlakeID getSnowFlakeIDEntity() {
        if(SNOW_FLAKE_ID_ENTITY != null) return SNOW_FLAKE_ID_ENTITY;
        throw new InvalidOperationException("你需要调用 initSnowFlakeIDEntity 方法初始化默认的雪花 ID 生成器才能调用本方法");
    }


    @Note("获取一个线程安全且不重复的 13 位以上的纯数字 ID")
    public static long newID() {
        return getNumberIDEntity().newID();
    }


    @Note("获取一个唯一的 13 位的纯数字 ID，并对数字顺序做混淆")
    public static long newShuffleID() {
        return getNumberIDEntity().newShuffleID();
    }

    @Note("开启自增 ID 功能，sourceID 是需要开始自增的原始 ID。" +
            "以后每次调用 incrementID 方法都会在该基础上进行自增。")
    public static void enableDefaultNumberIDIncrement(long sourceID) {
        getNumberIDEntity().enableIncrement(sourceID);
    }

    @Note("自增 ID 方法。在调用之前需要先调用本工具类的 enableDefaultNumberIDIncrement 开启功能并设置原始 ID")
    public static long incrementID(){
        return getNumberIDEntity().incrementID();
    }

    @Note("生成一个 18 位的雪花 ID")
    public static long newSnowFlakeID() {
        return getSnowFlakeIDEntity().nextID();
    }


    @Note("批量生成 number 个 13 位的数字 ID，整体按从小到大排序")
    public static TreeSet<Long> newBatchID(int number) {
        return getNumberIDEntity().newBatchID(number);
    }


    @Note("批量生成 number 个 13 位的乱序数字 ID，整体按从小到大排序")
    public static TreeSet<Long> newBatchShuffleId(int number) {
        return getNumberIDEntity().newBatchShuffleId(number);
    }

    @Note("批量生成 number 个 13 位的自增数字 ID，整体按从小到大排序")
    public static TreeSet<Long> newBatchIncrId(int number) {
        return getNumberIDEntity().newBatchIncrId(number);
    }

    @Note("批量生成 number 个 18 位雪花 ID，整体按从小到大排序")
    public static TreeSet<Long> newBatchSnowFlakeID(int number) {
        return getSnowFlakeIDEntity().newBatchSnowFlakeID(number);
    }

    /* *******************************************************************************************
     *
     *          批量生成字符串 ID
     *
     * *******************************************************************************************
     * */


    @Note("批量生成 number 个 UUID，并按自然排序排好返回")
    public static TreeSet<String> newBatchUUID(int number) {
        if(number <= 0) return new TreeSet<>();
        TreeSet<String> idSet = new TreeSet<>();
        for (int i = 0; i < number; i++) {
            idSet.add(newUUID());
        }
        return idSet;
    }


    @Note("批量生成 number 个经过替换【-】子串的 UUID，并按自然排序排好返回")
    public static TreeSet<String> newBatchUUID(int number, String replaceStr) {
        if(number <= 0) return new TreeSet<>();
        TreeSet<String> idSet = new TreeSet<>();
        for (int i = 0; i < number; i++) {
            idSet.add(newUUID(replaceStr));
        }
        return idSet;
    }


    @Note("批量生成 number 个去除【-】子串的 UUID，并按自然排序排好返回")
    public static TreeSet<String> newBatchUUID2(int number) {
        if(number <= 0) return new TreeSet<>();
        TreeSet<String> idSet = new TreeSet<>();
        for (int i = 0; i < number; i++) {
            idSet.add(newUUID2());
        }
        return idSet;
    }


    @Note("批量生成 number 个默认长度【21】、默认模板的 NanoID，并按自然排序排好返回")
    public static TreeSet<String> newBatchNanoID(int number) {
        return getStringIDEntity().newBatchNanoID(number);
    }


    @Note("批量生成 number 个指定长度、默认模板的 NanoID，并按自然排序排好返回")
    public static TreeSet<String> newBatchNanoID(int number, int length) {
        return getStringIDEntity().newBatchNanoID(number, length);
    }

    @Note("批量生成 number 个由指定随机数生成器、字符模板、长度制造的 NanoID，并按自然排序排好返回")
    public static TreeSet<String> newBatchNanoID(int number, Random random, char[] template, int length) {
        return getStringIDEntity().newBatchNanoID(number, random, template, length);
    }


    @Note("批量生成 number 个默认长度【21】、默认模板的字符串 ID，并按自然排序排好返回")
    public static TreeSet<String> newBatchStringID(int number) {
        return getStringIDEntity().newBatchStringID(number);
    }


    @Note("批量生成 number 个指定长度、默认模板的字符串 ID，并按自然排序排好返回")
    public static TreeSet<String> newBatchStringID(int number, int idLength) {
        return getStringIDEntity().newBatchStringID(number, idLength);
    }

    @Note("批量生成 number 个指定长度、指定的字符模板的字符串 ID，并按自然排序排好返回")
    public static TreeSet<String> newBatchStringID(int number, int idLength, char[] template) {
        return getStringIDEntity().newBatchStringID(number, idLength, template);
    }

    @Note("批量生成 number 个指定长度的 16 进制字符串 ID，并按自然排序排好返回")
    public static TreeSet<String> newBatch16BinaryID(int number, int idLength) {
        return getStringIDEntity().newBatch16BinaryID(number, idLength);
    }
}
